package com.luoyx.vjsb.activiti.controller;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.luoyx.vjsb.activiti.entity.ProcessDefinition;
import com.luoyx.vjsb.activiti.entity.TaskAssignee;
import com.luoyx.vjsb.activiti.service.IActivityService;
import com.luoyx.vjsb.activiti.service.IProcessDefinitionService;
import com.luoyx.vjsb.activiti.service.ITaskAssigneeService;
import com.luoyx.vjsb.common.util.AjaxResult;
import com.luoyx.vjsb.core.entity.SysRole;
import com.luoyx.vjsb.core.service.ISysRoleService;
import lombok.SneakyThrows;
import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * <p>
 * 流程定义
 * </p>
 *
 * @author luoyuanxiang <p>luoyuanxiang.github.io</p>
 * @since 2020/5/15 10:38
 */
@Controller
@RequestMapping("definition")
public class ProcessDefinitionController {

    @Resource
    private IProcessDefinitionService iProcessDefinitionService;

    @Resource
    private RepositoryService repositoryService;

    @Resource
    private IActivityService iActivityService;

    @Resource
    private ITaskAssigneeService iTaskAssigneeService;

    @Resource
    private ISysRoleService iSysRoleService;

    @PostMapping("list")
    @ResponseBody
    public AjaxResult<Page<ProcessDefinition>> list(ProcessDefinition processDefinition) {
        Page<ProcessDefinition> processDefinitionPage = iProcessDefinitionService.listProcessDefinition(processDefinition);
        return AjaxResult.success(processDefinitionPage);
    }

    /**
     * 通过模型id获取节点数据
     *
     * @param modelId 模型id
     * @return 1
     */
    @SneakyThrows
    @GetMapping("/activityListByMi")
    @ResponseBody
    public AjaxResult<List<Map<String, String>>> activityListByMi(String modelId) {
        Model model = repositoryService.createModelQuery().modelId(modelId).singleResult();
        if (model.getDeploymentId() == null) {
            return AjaxResult.error("模型还未发布!");
        }
        Collection<FlowElement> flowElements = iActivityService.activityListFlowElement(model.getId());
        List<Map<String, String>> list = new ArrayList<>(flowElements.size());
        flowElements.parallelStream().forEach(flowElement -> {
            Map<String, String> map = new HashMap<>(4);
            map.put("id", flowElement.getId());
            map.put("name", flowElement.getName());
            map.put("modelId", model.getId());
            TaskAssignee taskAssignee = iTaskAssigneeService.queryByModelIdAndActivityId(model.getId(), flowElement.getId());
            if (taskAssignee != null) {
                SysRole role = iSysRoleService.getById(taskAssignee.getRoleId());
                if (role != null) {
                    map.put("roleId", taskAssignee.getRoleId());
                    map.put("roleName", role.getRoleName());
                }
            }
            list.add(map);
        });
        return AjaxResult.success(list);
    }

    @DeleteMapping("/remove")
    @ResponseBody
    public AjaxResult<Integer> remove(String[] ids) {
        try {
            return AjaxResult.success(iProcessDefinitionService.deleteProcessDeploymentByIds(ids));
        } catch (Exception e) {
            return AjaxResult.error();
        }
    }

    @PatchMapping("/suspendOrActiveApply")
    @ResponseBody
    public AjaxResult<String> suspendOrActiveApply(String id, Integer status) {
        iProcessDefinitionService.suspendOrActiveApply(id, status);
        return AjaxResult.success();
    }


    /**
     * 读取流程资源
     *
     * @param processDefinitionId 流程定义ID
     * @param resourceName        资源名称
     */
    @RequestMapping(value = "/readResource")
    public void readResource(@RequestParam("pdid") String processDefinitionId,
                             @RequestParam("resourceName") String resourceName,
                             HttpServletResponse response)
        throws Exception {
        ProcessDefinitionQuery pdq = repositoryService.createProcessDefinitionQuery();
        org.activiti.engine.repository.ProcessDefinition pd = pdq.processDefinitionId(processDefinitionId).singleResult();

        // 通过接口读取
        InputStream resourceAsStream = repositoryService.getResourceAsStream(pd.getDeploymentId(), resourceName);

        // 输出资源内容到相应对象
        byte[] b = new byte[1024];
        int len = -1;
        while ((len = resourceAsStream.read(b, 0, 1024)) != -1) {
            response.getOutputStream().write(b, 0, len);
        }
    }

    /**
     * 转换流程定义为模型
     *
     * @param processDefinitionId 1
     * @return 1
     * @throws XMLStreamException 1
     */
    @PostMapping(value = "/convert2Model")
    @ResponseBody
    public AjaxResult<String> convertToModel(@Param("processDefinitionId") String processDefinitionId)
        throws XMLStreamException {
        org.activiti.engine.repository.ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
            .processDefinitionId(processDefinitionId).singleResult();
        InputStream bpmnStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(),
            processDefinition.getResourceName());
        XMLInputFactory xif = XMLInputFactory.newInstance();
        InputStreamReader in = new InputStreamReader(bpmnStream, StandardCharsets.UTF_8);
        XMLStreamReader xtr = xif.createXMLStreamReader(in);
        BpmnModel bpmnModel = new BpmnXMLConverter().convertToBpmnModel(xtr);

        BpmnJsonConverter converter = new BpmnJsonConverter();
        ObjectNode modelNode = converter.convertToJson(bpmnModel);
        Model modelData = repositoryService.newModel();
        modelData.setKey(processDefinition.getKey());
        modelData.setName(processDefinition.getResourceName());
        modelData.setCategory(processDefinition.getDeploymentId());

        ObjectNode modelObjectNode = new ObjectMapper().createObjectNode();
        modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, processDefinition.getName());
        modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, 1);
        modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, processDefinition.getDescription());
        modelData.setMetaInfo(modelObjectNode.toString());

        repositoryService.saveModel(modelData);

        repositoryService.addModelEditorSource(modelData.getId(), modelNode.toString().getBytes(StandardCharsets.UTF_8));

        return AjaxResult.success();
    }

}
